/**
 * @package Infinity-Seed
 * @subpackage view
 *
 * @copyright Copyright (C) 2012-2013 Exia.CESI
 * @author Paul MAGNIN, Arthur MERCIER, Jordan RICHET, Cyril SCHUMACHER
 */
package view;

import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

/**
 * Fenêtre les éléments d'interaction.
 * @author Cyril SCHUMACHER <cyril.schumacher at viacesi.fr>
 * @author Arthur MERCIER <arthur.mercier at viacesi.fr>
 * @author Jordan RICHET <paul.magnin at viacesi.fr>
 */
public class ActionWindow {
    // <editor-fold defaultstate="collapsed" desc="Attributs.">
    /**
     * Fenêtre.
     */
    protected JFrame frame;
    /**
     * Position de la fenêtre de simulation.
     */
    private Point point = new Point();
    /**
     * Bouton "Commencer la simulation".
     */
    private JButton _playButton;
    /**
     * Timer
     */
    private Timer _timer;
    /**
     * Bouton "Arrêter la simulation".
     */
    private JButton _stopButton;
    /**
     * Bouton "Pas à pas".
     */
    private JButton _nextButton;
    /**
     * Thread pour la simulation.
     */
    protected Thread simulationThread;
    /**
     * Configuration.
     */
    private infinity.seed.Configuration _configuration;
    /**
     * Fenêtre GridWindow.
     */
    private GridWindow _gridWindow;
    /**
     * Timer
     */
    private Timer timer;
    /**
     * Fenêtre SimulatorWindow.
     */
    private SimulatorWindow _simulatorWindow;
    /**
     * Fenêtre contenant les statistiques.
     */
    private StatsWindow _statsWindow;
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Méthodes.">
    // <editor-fold defaultstate="collapsed" desc="Constructeur.">
    /**
     * Constructeur.
     */
    public ActionWindow(SimulatorWindow simulatorWindow) {
        // Récupère une instance de la classe Configuration.
        this._configuration = infinity.seed.Configuration.getInstance();
        // Création de la fenêtre.
        this.frame = new JFrame("Action");
        
        // Sauvegarde l'instance de la fenêtre.
        this._simulatorWindow = simulatorWindow;

        // Empêche le client de fermer et de redimensionner la fenêtre.
        this.frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.frame.setResizable(false);

        // Initialise les composants de la fenêtre.
        this._InitializeComponent();

        this.frame.setBackground(Color.decode(_configuration.get("jwindow.background")));
        this.frame.setUndecorated(true);
        // Redimensionne selon les composants,
        this.frame.pack();
        // met en premier plan et y reste,
        this.frame.toFront();
        // positionne  et affiche la fenêtre.
        this.frame.setLocation(425, 305); // fenetre avec le play
        this.frame.setVisible(true);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Initialise les composants.">
    /**
     * Initialise les composants.
     */
    private void _InitializeComponent() {
        // Utilisation de police personnalisée.
        infinity.seed.CustomFont customFont = new infinity.seed.CustomFont();

        // Lie les événements à la fenêtre.
        ActionWindowEvent windowEvent = new ActionWindowEvent();
        this.frame.addMouseListener(windowEvent);
        this.frame.addMouseMotionListener(windowEvent);

        // Ajoute une disposition au contenu principale.
        BorderLayout contentPaneLayout = new BorderLayout();
        this.frame.getContentPane().setLayout(contentPaneLayout);
        this.frame.getRootPane().setBorder(BorderFactory.createLineBorder(Color.black));

        // Barre de titre.
        JPanel titlePanel = new JPanel();
        this.frame.getContentPane().add(titlePanel, BorderLayout.PAGE_START);
        titlePanel.setBackground(Color.decode(_configuration.get("jwindow.background")));
        titlePanel.setLayout(new FlowLayout(FlowLayout.RIGHT));

        JPanel spacePanel = new JPanel();
        spacePanel.setPreferredSize(new Dimension(0, 5));
        titlePanel.add(spacePanel);

        JPanel actionPanel = new JPanel();
        actionPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
        this.frame.getContentPane().add(actionPanel);

        JButton resetButton = new JButton("i");
        resetButton.setPreferredSize(new Dimension(50, 50));
        resetButton.setToolTipText(this._configuration.get("resetButton.tooltip"));
        resetButton.setFont(customFont.getFont("/resources/ll_record/ll_recor.ttf", 50));
        resetButton.setForeground(Color.decode(_configuration.get("jbutton.background")));
        resetButton.setOpaque(false);
        resetButton.setContentAreaFilled(false);
        resetButton.setBorderPainted(false);
        resetButton.setBorder(BorderFactory.createEmptyBorder());
        resetButton.addMouseListener(new ResetButtonEvents());
        actionPanel.add(resetButton);

        // Bouton "Arrêter la simulation".
        this._stopButton = new JButton("x");
        this._stopButton.setEnabled(false);
        this._stopButton.setPreferredSize(new Dimension(50, 50));
        this._stopButton.setToolTipText(this._configuration.get("stopButton.tooltip"));
        this._stopButton.setFont(customFont.getFont("/resources/ll_record/ll_recor.ttf", 50));
        this._stopButton.setForeground(Color.decode(_configuration.get("jbutton.background")));
        this._stopButton.setOpaque(false);
        this._stopButton.setContentAreaFilled(false);
        this._stopButton.setBorderPainted(false);
        this._stopButton.setBorder(BorderFactory.createEmptyBorder());
        this._stopButton.addMouseListener(new StopButtonEvents());
        actionPanel.add(this._stopButton);

        // Bouton "Commencer la simulation".
        this._playButton = new JButton("u");
        this._playButton.setPreferredSize(new Dimension(50, 50));
        this._playButton.setToolTipText(this._configuration.get("playButton.tooltip"));
        this._playButton.setFont(customFont.getFont("/resources/ll_record/ll_recor.ttf", 50));
        this._playButton.setForeground(Color.decode(_configuration.get("jbutton.background")));
        this._playButton.setOpaque(false);
        this._playButton.setContentAreaFilled(false);
        this._playButton.setBorderPainted(false);
        this._playButton.setBorder(BorderFactory.createEmptyBorder());
        this._playButton.addMouseListener(new PlayButtonEvents());
        actionPanel.add(this._playButton);

        // Bouton "Avancer pas par pas".
        this._nextButton = new JButton("{");
        this._nextButton.setPreferredSize(new Dimension(50, 50));
        this._nextButton.setToolTipText(this._configuration.get("nextButton.tooltip"));
        this._nextButton.setFont(customFont.getFont("/resources/ll_record/ll_recor.ttf", 50));
        this._nextButton.setForeground(Color.decode(_configuration.get("jbutton.background")));
        this._nextButton.setOpaque(false);
        this._nextButton.setContentAreaFilled(false);
        this._nextButton.setBorderPainted(false);
        this._nextButton.setBorder(BorderFactory.createEmptyBorder());
        this._nextButton.addMouseListener(new NextButtonEvents());
        actionPanel.add(this._nextButton);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Définit la fenêtre GridWindow.">
    /**
     * Définit la fenêtre GridWindow.
     * @param actionWindow Instance de la classe ActionWindow.
     */
    public void setGridWindow(GridWindow gridWindow) {
        this._gridWindow = gridWindow;
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Définit la fenêtre StatsWindow.">
    /**
     * Définit la fenêtre StatsWindow.
     * @param statsWindow Instance de la classe StatsWindow.
     */
    public void setStatsWindow(StatsWindow statsWindow) {
        this._statsWindow = statsWindow;
    }
    // </editor-fold>
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Evénements.">
    // <editor-fold defaultstate="collapsed" desc="Gestion des évènements de la fenêtre.">
    /**
     * Gestion des évènements de la fenêtre.
     */
    private class ActionWindowEvent extends MouseAdapter {
        /**
         * Recupere la position du curseur.
         * @param e Parametres.
         */
        @Override
        public void mousePressed(MouseEvent e) {
            point.x = e.getX();
            point.y = e.getY();
        }

        /**
         * Selon la position du curseur, on déplace la fenêtre.
         * @param e Parametres.
         */
        @Override
        public void mouseDragged(MouseEvent e) {
            JFrame frame = (JFrame) e.getSource();
            Point position = frame.getLocation();
            frame.setLocation(position.x + e.getX() - point.x, position.y + e.getY() - point.y);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Gestion des évènements pour le bouton "Commencer la simulation".">
    /**
     * Gestion des évènements pour le bouton "Commencer la simulation".
     */
    private class PlayButtonEvents extends MouseAdapter {
        /**
         * Lorsque le client clique sur le bouton, la
         * @param e Paramètres.
         */
        @Override
        public void mousePressed(MouseEvent e) {
            // Evite que le client clique à nouveau sur le bouton "Commencer la simulation".
            if ((simulationThread == null) || (simulationThread.isAlive() == false)) {
                /**
                 * Demarre un nouveau thread (exécuter en parallèle).
                 * @see <a href="http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Runnable.html">Runnable</a>
                 */
                simulationThread = new Thread(new Runnable() {
                    /**
                     * Commencer l'exécution du thread. {@inheritDoc}
                     */
                    @Override
                    public void run() {
                        // Nombre de pas effectué.
                        int step = 0; 
                        // Nombre de pas saisis.
                        while (step < _statsWindow.getStepNumber()) {
                            _gridWindow.gridCell.setGrid(_simulatorWindow.simulate());
                            _gridWindow.frame.repaint();
                            _statsWindow.updateStats();
                            try {
                                Thread.sleep(_statsWindow.getTimeNumber() * 1000);
                            } catch (InterruptedException ex) {
                                Logger.getLogger(SimulatorWindow.class.getName()).log(Level.INFO, null, ex);
                                break;
                            }
                            step++;
                        }
                        
                        // Active le bouton "Commencer la simulation" et le bouton "Avancer pas à pas". 
                        _playButton.setEnabled(true);
                        _nextButton.setEnabled(true);
                        // Désactive le bouton "Arreter la simulation".
                        _stopButton.setEnabled(false);
                    }
                });

                // Exécute le thread.
                simulationThread.start();

                // Désactive le bouton "Commencer la simulation" et le bouton "Avancer pas a pas".
                _playButton.setEnabled(false);
                _nextButton.setEnabled(false);
                // Active le bouton "Arrêter la simulation".
                _stopButton.setEnabled(true);
            }
        }
    }
    // </editor-fold>  
    // <editor-fold defaultstate="collapsed" desc="Gestion des évènements pour le bouton "Arrêter la simulation".">
    /**
     * Gestion des évènements pour le bouton "Arrêter la simulation".
     */
    private class StopButtonEvents extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            // Verifie si un thread existe.
            if ((simulationThread != null) && (simulationThread.isInterrupted() == false)) {
                // La methode Thread::interrupt() remplace la methode Thread::stop() qui est obselète (provoque de nombreux blocage).
                simulationThread.interrupt();
                // Active le bouton "Commencer la simulation" et le bouton "Avancer pas à pas". 
                _playButton.setEnabled(true);
                _nextButton.setEnabled(true);
                // Désactive le bouton "Arreter la simulation".
                _stopButton.setEnabled(false);
            }
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Gestion des evenements pour le bouton "Avancer pas à pas".">
    /**
     * Gestion des evenements pour le bouton "Avancer pas par pas".
     */
    private class NextButtonEvents extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            if ((simulationThread == null) || (simulationThread.isAlive() == false)) {
                // Redessine la grille.
                _gridWindow.gridCell.setGrid(_simulatorWindow.simulate());
                _statsWindow.updateStats();
                _gridWindow.frame.repaint();
            }
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Gestion des évènements pour le bouton "Initialiser la grille".">
    /**
     * Gestion des évènements pour le bouton "Initialiser la grille".
     */
    private class ResetButtonEvents extends MouseAdapter {

        /**
         * Lorsque le client clique sur le bouton, la grille est initialisé.
         *
         * @param e Paramètres.
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            _gridWindow.grid = new int[_gridWindow.grid.length][_gridWindow.grid[0].length];
            _simulatorWindow.array = _gridWindow.grid;
            _gridWindow.gridCell.setGrid(_gridWindow.grid);
            _gridWindow.frame.repaint();
            _statsWindow.updateStats();
        }
    }
    // </editor-fold>
    // </editor-fold>
}
